package org.shj.basic.extendclass

class Animal{
  val range: Int = 10
  val env: Array[Int] = new Array[Int](range)
}

class Ant extends Animal{
  override val range = 2
}

object ConstructOrder {
  def main(args: Array[String]): Unit = {
    val ant = new Ant()
    println(ant.env.length)
    /**
     * 以上会输出 0。 为什么呢？
     * 超类的构造器优先于子类的构造器运行。事情发生的过程是这样的：
     * 1. Ant 的构造器在做它自己的构造之前，调用 Animal 的构造器
     * 2. Animal 的构造器将它的 range 设为 10
     * 3. Animal 的构造器初始化 env 数组，调用 range() 取值器
     * 4. 该方法被重写以输出（还未初始化的） Ant 类的 range 字段值
     * 5. range 方法返回 0（这是对象被分配空间时所有整型字段的初始值）
     * 6. env 被设为长度为 0 的数组
     * 7. Ant 构造器继续执行，将 range 设为 2
     * 
     * 虽然 range 字段看上去可能是 10 或者 2， 但是 env 被设成了长度为 0 的数组。
     * 这里的教训是： 在构造器内不应该依赖 val 的值
     * 
     * 解决方法：
     * 1. 将 val 声明 为 final。 这样很安全，但是不灵活
     * 2. 在超类中将 val 声明为 lazy。 这样很安全，但是不高效
     * 3. 在子类中使用“提前定义语法”
     */
  }
}

//提前定义语法的方式
class Dog extends {
  override val range = 2
} with Animal